import {
  ARRAY_TYPES,
  EmitChange,
  FormEventType,
  HandleChange,
  Maskable,
  TYPE_BOOL,
  TYPE_BOUNDARY_DISPLACEMENT,
  TYPE_BOUNDARY_LOAD,
  TYPE_DOUBLE,
  TYPE_EXPRESSION,
  TYPE_GEOMETRIES_NEXTMESH,
  TYPE_GROUP,
  TYPE_INT,
  TYPE_MULTI_SELECT_TREE,
  TYPE_DYNAMIC_TABLE,
  TYPE_MATERIAL_SET,
  TYPE_SURFACE_INTERACTION_SET,
  TYPE_OPTION,
  TYPE_SET_ELEMENT,
  TYPE_SET_NODE,
  TYPE_SET_SURFACE,
  TYPE_SET_REFER_POINT,
  TYPE_TABULAR,
} from '@app-nextmesh/types';
import { events } from '@app-nextmesh/utils';
import { Card } from 'antd';
import { isArray, isEmpty, isObject, isPlainObject } from 'lodash';
import { useEffect, useRef, useState } from 'react';
import {
  ArrayN,
  BoundarySetSelect,
  CheckBox,
  ElementSetSelect,
  Entity,
  ErrorTips,
  ExpressionInput,
  FormField,
  FormFieldSet,
  FormNativeSelect,
  GeometriesSetSelect,
  Group,
  MaterialSelect,
  SurfaceInteractionSelect,
  Tabular,
  ValueField,
  MaterialCalculix,
  DynamicTable,
} from '.';
import ObjectType from '../ObjectType';
import { IJSONFormProps } from './types';
import { getLabel, isEntityTypes, makeDefaultFormItem } from './utils';

/**
 * 通过formFormat和formData等生成Form表单项
 */
export default function JSONFormField({
  readonly,
  initName,
  formFormat,
  formData,
  onChange,
  indicesAssigned,
  switchedOnEntityGroup,
  onSwitchEntityGroup,
}: IJSONFormProps) {
  const formDataRef = useRef(formData);
  const [form, setForm] = useState(undefined);
  const [maskableChecked, setMaskableChecked] = useState(false);
  const [show, setShow] = useState(true);

  useEffect(() => {
    const newForm = formData;
    formDataRef.current = newForm;
    setForm(newForm);
  }, [formData]);
  useEffect(() => {
    if (formFormat[Maskable]) {
      setMaskableChecked(formData ? true : false);
    }
  }, [formFormat, formData]);
  useEffect(() => {
    if (!formFormat[HandleChange]) {
      return () => {};
    }
    events.on(FormEventType.TypeChanged, handleFormChangeEvent);
    return () => {
      events.off(FormEventType.TypeChanged, handleFormChangeEvent);
    };
  }, [formFormat]);
  useEffect(() => {
    if (!formFormat[EmitChange]) {
      return;
    }
    const type = formData?.Type;
    const value = formData?.Value;
    if (value) {
      if (isPlainObject(value)) {
        if (type) {
          // TODO hack it，待优化；在整个表单都渲染之后，再触发
          setTimeout(() =>
            events.emit(FormEventType.TypeChanged, [initName, type]),
          );
        }
      } else {
        // TODO hack it，待优化；在整个表单都渲染之后，再触发
        setTimeout(() =>
          events.emit(FormEventType.TypeChanged, [initName, value]),
        );
      }
    }
  }, [initName, formFormat, formData]);
  const handleFormChangeEvent = (names: string[]) => {
    if (!names || names.length === 0) {
      return;
    }
    let handleChange = formFormat[HandleChange];
    if (handleChange[names[0]]) {
      let changeShow: boolean = false;
      // 判断是否多选的状态下进行展示选择对应的表单
      for (const name of names) {
        if (isArray(name)) {
          changeShow = name.some((value) => handleChange[value]);
        } else {
          handleChange = handleChange[name];
          changeShow = handleChange;
        }
        if (!changeShow) {
          break;
        }
      }
      if (changeShow) {
        if (!formFormat.Maskable) {
          // 初始化的时候添加处理多选得到表单不进行默认展示。
          if (!formDataRef.current) {
            const newForm = makeDefaultFormItem(formFormat);
            formDataRef.current = newForm;
          }
          setForm(formDataRef.current);
          onChange(initName, formDataRef.current);
        }
      } else {
        onChange(initName, undefined);
      }
      setShow(changeShow);
    } else if (names[1]) {
      if (names[1].length === 0) {
        // 如果name是空数组则清空渲染表单数据
        setShow(false);
        onChange(initName, undefined);
      }
    }
  };

  if (!form) {
    return <></>;
  }
  if (!isPlainObject(formFormat)) {
    return (
      <ErrorTips>{`${initName}的值格式错误，必须是一个JSON对象`}</ErrorTips>
    );
  }
  if (!Object.prototype.hasOwnProperty.call(formFormat, 'Type')) {
    return <ErrorTips>{`${initName}缺少Type字段`}</ErrorTips>;
  }

  const handleChange = (value: any) => {
    formDataRef.current = value;
    onChange(initName, value);

    const type = value?.Type ?? value;
    if (formFormat[EmitChange] && type) {
      events.emit(FormEventType.TypeChanged, [initName, type]);
    }
  };

  const type = formFormat.Type; // 每项首先有一个 Type 字段
  const maskable = formFormat.Maskable; // 是否可被隐藏
  const formatUnit = formFormat.Unit;
  let label: string = initName;
  if (Object.prototype.hasOwnProperty.call(formFormat, 'Label')) {
    label = formFormat.Label;
  }
  if (label) {
    label = getLabel(label);
  }
  if (!type) {
    return (
      <ErrorTips>{`${initName}的Type:${type}，是无效的Type类型`}</ErrorTips>
    );
  }

  let component: JSX.Element;
  if (isEntityTypes(type)) {
    // 选择顶点、边、面、体
    component = (
      <Entity
        disabled={readonly}
        name={initName}
        switchedOn={initName === switchedOnEntityGroup}
        type={type}
        label={label}
        value={form.Value}
        assignedValues={indicesAssigned}
        onChange={handleChange}
        onClick={onSwitchEntityGroup}
      />
    );
  } else if (ARRAY_TYPES.includes(type)) {
    // 输入多个数值类型
    component = (
      <ArrayN
        disabled={readonly}
        type={type}
        label={label}
        value={{ Value: form.Value, Unit: form.Unit }}
        units={formatUnit}
        onChange={handleChange}
      />
    );
  } else if ([TYPE_DOUBLE, TYPE_INT, TYPE_BOOL].includes(type)) {
    // 数值类型
    component = (
      <ValueField
        disabled={readonly}
        type={type}
        label={label}
        value={{ Value: form.Value, Unit: form.Unit }}
        units={formatUnit}
        onChange={handleChange}
      />
    );
  } else if (type === TYPE_EXPRESSION) {
    component = (
      <FormField label={label}>
        <ExpressionInput
          disabled={readonly}
          value={{ Value: form.Value, Unit: form.Unit }}
          units={formatUnit}
          onChange={handleChange}
        />
      </FormField>
    );
  } else if (type === TYPE_TABULAR) {
    component = (
      <Tabular
        formFormat={formFormat}
        disabled={readonly}
        value={form.Value}
        onChange={handleChange}
      />
    );
  } else if (
    type === TYPE_SET_NODE ||
    type === TYPE_SET_ELEMENT ||
    type === TYPE_SET_SURFACE ||
    type === TYPE_SET_REFER_POINT
  ) {
    component = (
      <FormField label={label}>
        <ElementSetSelect
          disabled={readonly}
          type={type}
          value={form.Value}
          onChange={handleChange}
        />
      </FormField>
    );
  } else if (
    type === TYPE_BOUNDARY_DISPLACEMENT ||
    type === TYPE_BOUNDARY_LOAD
  ) {
    component = (
      <FormField label={label}>
        <BoundarySetSelect
          disabled={readonly}
          type={type}
          value={form.Value}
          onChange={handleChange}
        />
      </FormField>
    );
  } else if (type === TYPE_GEOMETRIES_NEXTMESH) {
    component = (
      <FormField label={label}>
        <GeometriesSetSelect
          disabled={readonly}
          type={type}
          value={form.Value}
          onChange={handleChange}
        />
      </FormField>
    );
  } else if (type === TYPE_MATERIAL_SET) {
    component = (
      <FormField label={label}>
        <MaterialSelect
          disabled={readonly}
          value={form.Value}
          onChange={handleChange}
        />
      </FormField>
    );
  } else if (type === TYPE_MULTI_SELECT_TREE) {
    component = (
      <FormField label={label}>
        <MaterialCalculix
          disabled={readonly}
          value={form.Value}
          options={formFormat.Options}
          multiple={formFormat.multiple}
          onChange={handleChange}
        />
      </FormField>
    );
  } else if (type === TYPE_DYNAMIC_TABLE) {
    component = (
      <FormField label={label}>
        <DynamicTable
          disabled={readonly}
          value={form.Value}
          columns={formFormat.Columns}
          table={formFormat.Options}
          tableType={formFormat.TableType}
          onChange={handleChange}
        />
      </FormField>
    );
  } else if (type === TYPE_SURFACE_INTERACTION_SET) {
    component = (
      <FormField label={label}>
        <SurfaceInteractionSelect
          disabled={readonly}
          value={form.Value}
          onChange={handleChange}
        />
      </FormField>
    );
  } else if (type === TYPE_OPTION) {
    component = (
      <FormField label={label}>
        <FormNativeSelect
          disabled={readonly}
          value={form.Value}
          multiple={formFormat.multiple}
          options={formFormat.Options.map((option) => {
            return { value: option, label: getLabel(option) };
          })}
          onChange={handleChange}
        />
      </FormField>
    );
  } else if (type === TYPE_GROUP) {
    component = (
      <FormFieldSet>
        <Group
          readonly={readonly}
          label={label}
          typeObject={formFormat}
          form={form.Value}
          onInputChange={handleChange}
        />
      </FormFieldSet>
    );
  } else if (isPlainObject(type) && !isEmpty(type)) {
    // 根据 form.Type 的值，获取或生成默认的完整formData，
    // 传递给JSONFormatForm组件，生成表单界面
    /**
     * type 格式示例：
      {
        "Hard": {},
        "Linear": {
          "c_0": {
            "Type": "double",
            "Default": 0.0
          },
          "K": {
            "Type": "double",
            "Default": 0.0
          },
          "\\sigma_\\infty": {
            "Type": "double",
            "Default": 0.0
          }
        }
      }
     */
    component = (
      <FormFieldSet>
        <ObjectType
          readonly={readonly}
          formFormat={formFormat}
          form={form}
          onInputChange={handleChange}
          indicesAssigned={indicesAssigned}
          switchedOnEntityGroup={switchedOnEntityGroup}
          handleSwitchEntityGroup={onSwitchEntityGroup}
        />
      </FormFieldSet>
    );
  } else {
    component = (
      <ErrorTips>{`${initName}的Type:${type}，无效的Type类型`}</ErrorTips>
    );
  }
  if (maskable) {
    const handelCheckChange = (checked: boolean) => {
      setMaskableChecked(checked);
      const value = checked ? form : undefined;
      handleChange(value);
    };

    component = (
      <FormFieldSet>
        <Card styles={{ body: { padding: 5 } }}>
          <CheckBox
            disabled={readonly}
            label={label}
            checked={maskableChecked}
            onChange={handelCheckChange}
          />
          {maskableChecked && component}
        </Card>
      </FormFieldSet>
    );
  } else {
    // 非maskable，如果是对象，显示卡片；否则会导致多层嵌套卡片
    if (isPlainObject(type) && !isEmpty(type)) {
      component = (
        <FormFieldSet>
          <Card styles={{ body: { padding: 5 } }}>
            <label>{label}</label>
            {component}
          </Card>
        </FormFieldSet>
      );
    }
  }
  return show && component;
}
